package com.hunt.util;

import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author ouyangan
 * @Date 2017/1/13/17:02
 * @Description 安全验证工具类
 */
public class OathUtil {
    private static final Logger log = LoggerFactory.getLogger(OathUtil.class);


    /**
     * @param map
     * @param keyValueApendStr
     * @param paramApendStr
     * @param urlEncode
     * @param removeKey
     * @throws UnsupportedEncodingException
     * @Author ouyangan
     * @Date 2017-1-16 14:42:30
     * @Description 基础方法, 后续签名可在此上面拓展, 生成待签名字符串, 适用于类型为map的参数
     */
    public static String genareteSignStringForMap(Map<String, String> map, String keyValueApendStr, String paramApendStr, boolean urlEncode, String... removeKey) throws UnsupportedEncodingException {
        //去除不参与签名参数
        for (String key : removeKey) {
            map.remove(key);
        }
        List<String> list = new ArrayList<>();
        //空值不参与签名
        list.addAll(map
                .keySet()
                .stream()
                .filter(s -> (StringUtils.hasText(map.get(s))))
                .collect(Collectors.toList())
        );
        Collections.sort(list);
        StringBuffer buffer = new StringBuffer();
        for (String s : list) {
            log.debug("key:{} value:{}", s, map.get(s));
            if (urlEncode) {
                buffer.append(s).append(keyValueApendStr).append(URLEncoder.encode(map.get(s), "utf-8")).append(paramApendStr);
            } else {
                buffer.append(s).append(keyValueApendStr).append(map.get(s)).append(paramApendStr);
            }
        }
        return buffer.toString();
    }

    /**
     * @param object
     * @param keyValueApendStr
     * @param paramApendStr
     * @param secret
     * @param secretAppendStr
     * @param urlEncode
     * @param removeKey
     * @return
     * @throws UnsupportedEncodingException
     * @Author ouyangan
     * @Date 2017-1-16 14:43:47
     * @Description 基础方法, 后续签名可在此上面拓展, 生成待签名字符串, 适用于类型为JavaBean的参数
     */
    public static String genareteSignStringForObject(Object object, String keyValueApendStr, String paramApendStr, boolean urlEncode, String... removeKey) throws UnsupportedEncodingException {
        Map<Object, Object> beanMap = new BeanMap(object);
        Map<String, String> map = new HashMap<>();
        for (Object key : beanMap.keySet()) {
            Object value = beanMap.get(key);
            if ((value != null) && (!Objects.equals(key.toString(), "class"))) {
                map.put(key.toString(), value.toString());
            }
        }
        //去除不参与签名参数
        for (String key : removeKey) {
            map.remove(key);
        }
        List<String> list = new ArrayList<>();
        //排序
        list.addAll(map
                .keySet()
                .stream()
                .filter(s -> StringUtils.hasText(map.get(s)))
                .collect(Collectors.toList())
        );
        Collections.sort(list);
        StringBuffer buffer = new StringBuffer();
        for (String s : list) {
            log.debug("key:{} value:{}", s, map.get(s));
            if (urlEncode) {
                buffer.append(s).append(keyValueApendStr).append(URLEncoder.encode(map.get(s), "utf-8")).append(paramApendStr);
            } else {
                buffer.append(s).append(keyValueApendStr).append(map.get(s)).append(paramApendStr);
            }
        }
        return buffer.toString();
    }

    /**
     * @param object 签名对象
     * @param secret 密钥
     * @return
     * @throws UnsupportedEncodingException
     * @Author ouyangan
     * @Date 2017-1-16 14:51:30
     * @Description 淘宝开放平台参数签名, 适用于对象
     */
    public static Map<String, String> taoBaoSignature(Object object, String secret) throws UnsupportedEncodingException {
        String string = secret + genareteSignStringForObject(object, "", "", false) + secret;
        log.debug("淘宝.待签名字符串:{}", string);
        String sign = DigestUtils.md5Hex(string.getBytes()).toUpperCase();
        log.debug("淘宝.签名.{}", sign);
        //转换为map
        BeanMap beanMap = new BeanMap(object);
        Map<String, String> map = new HashMap<>();
        for (Object key : beanMap.keySet()) {
            Object value = beanMap.get(key);
            if ((value != null) && (!Objects.equals(key.toString(), "class"))) {
                map.put(key.toString(), value.toString());
            }
        }
        map.put("sign", sign);
        return map;
    }

    /**
     * @param map
     * @param secret
     * @return
     * @throws UnsupportedEncodingException
     * @Author ouyangan
     * @Date 2017-1-16 14:53:13
     * @Description 淘宝开放平台签名, 适用于map
     */
    public static Map<String, String> taoBaoSignature(Map<String, String> map, String secret) throws UnsupportedEncodingException {
        String string = secret + genareteSignStringForObject(map, "", "", false) + secret;
        log.debug("淘宝.待签名字符串:{}", string);
        String sign = DigestUtils.md5Hex(string.getBytes()).toUpperCase();
        log.debug("淘宝.签名.{}", sign);
        //转换为map
        map.put("sign", sign);
        return map;
    }


    /**
     * @param length 长度
     * @return
     * @Author ouyangan
     * @Date 2017-1-16 14:58:20
     * @Description 生成特定长度的数字验证码
     */
    public static String generateOathCode(int length) {
        String random = RandomStringUtils.random(length, "0123456789");
        log.debug("random:{}", random);
        return random;
    }

}
